﻿using Microsoft.AspNetCore.Mvc.Filters;
using Service.Core.Redis.Services;
using Microsoft.Extensions.DependencyInjection;
using System.Collections.Concurrent;
using System.Reflection;
using Service.Framework;

namespace Service.Core.Filters
{
    /// <summary>
    /// 对接口模型验证
    /// </summary>
    public class ApiCheckModelAttribute : ActionFilterAttribute
    {

        // 静态线程安全的缓存字典
        private static readonly ConcurrentDictionary<(Type, string), PropertyInfo> _propertyCache = new();


        private readonly string[] _parameterNames;

        private readonly string _verificationParameterName;




        /// <summary>
        /// 验证码验证的构造函数
        /// </summary>
        /// <param name="parameterNames">验证码key入参名称</param>
        /// <param name="verificationParameterName">验证码验证参数名称</param>
        public ApiCheckModelAttribute(string[] parameterNames, string verificationParameterName)
        {
            _parameterNames = parameterNames ?? throw new ArgumentNullException(nameof(parameterNames));
            _verificationParameterName = verificationParameterName ?? throw new ArgumentNullException(nameof(verificationParameterName));
        }

        /// <summary>
        /// 默认构造函数
        /// </summary>
        public ApiCheckModelAttribute()
        {
        }


        /// <summary>
        /// 每次请求Action之前发生，，在行为方法执行前执行
        /// </summary>
        /// <param name="context"></param>
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            if (!context.ModelState.IsValid)
            {
                var messages = new List<string>();
                var keys = context.ModelState.Keys;
                var values = context.ModelState.Values;
                foreach (var value in keys.Select(item => context.ModelState.FirstOrDefault(w => w.Key == item).Value))
                {
                    messages.AddRange(value.Errors.Select(err => err.ErrorMessage));
                }

                if (messages.Count > 0)
                {
                    throw new LogicErrorException(messages.FirstOrDefault()!);
                }
            }
            if (_parameterNames is not null && _verificationParameterName is not null)
            {
                var key = GetKey(context);
                var redisService = context.HttpContext.RequestServices.GetService<IRedisService>();
                var redisValue = redisService.Database.StringGetAsync(key).GetAwaiter().GetResult();
                var value = GetValue(context);
                redisService.Database.KeyDeleteAsync(key).GetAwaiter().GetResult();
                if (!value.Equals(redisValue.ToString(), StringComparison.OrdinalIgnoreCase))
                {
                    throw new LogicErrorException("验证码错误，请稍后再试。");
                }
            }
            return;

        }

        /// <summary>
        /// 获取Key
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        protected virtual string GetKey(ActionExecutingContext context)
        {
            var controllerName = context.Controller.GetType().Name;
            var actionName = context.ActionDescriptor.RouteValues["action"];
            var key = string.Empty;
            if (context.ActionArguments is null)
            {
                throw new ArgumentNullException(nameof(context.ActionArguments));
            }
            foreach (var parameterName in _parameterNames)
            {
                key += GetPropertyValue(context, parameterName);
            }
            return $"{controllerName}:{actionName}:{key}";
        }


        /// <summary>
        /// 获取value
        /// </summary>
        /// <param name="context"></param>
        /// <exception cref="ArgumentNullException"></exception>
        /// <returns></returns>
        protected virtual string GetValue(ActionExecutingContext context)
        {
            if (context.ActionArguments is null)
            {
                throw new ArgumentNullException(nameof(context.ActionArguments));
            }
            var value = GetPropertyValue(context, _verificationParameterName);
            return value?.ToString() ?? "";
        }

        protected virtual object? GetPropertyValue(ActionExecutingContext context, string name)
        {
            foreach (var arg in context.ActionArguments.Values)
            {
                if (arg == null)
                    continue;
                // 从缓存获取 PropertyInfo，不存在时自动反射并缓存
                var property = _propertyCache.GetOrAdd(
                    (arg.GetType(), name),
                    key => key.Item1.GetProperty(key.Item2, BindingFlags.Public | BindingFlags.Instance)
                );

                if (property != null)
                {
                    return property.GetValue(arg);
                }
            }
            return null;
        }







        public static string GetRequestValue(ActionExecutingContext context, string key)
        {
            // 1. 尝试从查询参数获取
            if (context.HttpContext.Request.Query.TryGetValue(key, out var queryValue))
                return queryValue.ToString();

            // 2. 尝试从路由值获取
            if (context.RouteData.Values.TryGetValue(key, out var routeValue))
                return routeValue?.ToString();

            // 3. 尝试从请求头获取
            if (context.HttpContext.Request.Headers.TryGetValue(key, out var headerValue))
                return headerValue.ToString();

            // 4. 尝试从表单获取
            if (context.HttpContext.Request.HasFormContentType &&
                context.HttpContext.Request.Form.TryGetValue(key, out var formValue))
                return formValue;

            return null;
        }

    }
}
